# !/usr/bin/env python
# coding:UTF-8
# 1 导入模块
import re
import pandas as pd
from pyecharts.charts import *
import pyecharts.options as opts
from pyecharts.globals import JsCode
from pyecharts.globals import ThemeType
from pyecharts.globals import SymbolType
import matplotlib.pyplot as plt

import warnings

warnings.filterwarnings("ignore")
plt.style.use("fivethirtyeight")

# 2.数据处理
# 读取数据
concat_accid = pd.read_excel('./data/concat_accid.xlsx')
new_accid = concat_accid.copy()
print(new_accid.head())

# 数据清洗
new_accid['driverresponsibility'].value_counts()

# 重置一下索引
new_accid.reset_index(drop=True,inplace=True)

# 删除不负责任的数据
new_accid.drop(new_accid[new_accid['driverresponsibility'] == '不负责任'].index,axis=0,inplace=True)

# 事故类型处理
new_accid['driverfault'].value_counts().index

new_accid.drop(new_accid[new_accid['driverfault']==''].index,inplace=True)
new_accid.reset_index(drop=True,inplace=True)
new_accid.shape

# 其他字段处理
new_accid['sex'].value_counts()

# 拿到驾照时的数据
new_accid['cclzrq'].value_counts().sort_index()
new_accid = new_accid[new_accid['cclzrq'].apply(lambda x:x[:2] in ['19','20'])]

# 出生年月的异常值
new_accid['brith'].value_counts().sort_index()
new_accid['brith'] = new_accid['brith'].apply(lambda x:x if x[:2] == '19' else '')
new_accid.drop(new_accid[new_accid['brith'] == ''].index,inplace=True)
new_accid.reset_index(inplace=True,drop=True)

# 保存处理后的数据
new_accid.to_csv('./data/new_accid.csv',index=False)


# 3 数据可视化
width,height = 1920,900
base_itemstyle = {
    'normal':{
        'shadowBlur':4,
        'shadowOffsetY':4,
        'shadowOffsetX':4,
        'barBorderRadius':[8,8,8,8],
        'opacity':1
    }
}

itemstyle = {
    'normal':{
        'shadowColor':'rgab(0,0,0,1)', # 阴影颜色
        'shadowBlur':4, # 阴影大小
        'shadowOffsetY':4, # y轴方向阴影偏移
        'shadowOffsetX':4, # x轴方向阴影偏移
        'borderRadius':4,
        'opacity':1
    }
}

# 汽车颜色分析
def get_pic1():
    car_color = new_accid['carcolor'].str[:1].value_counts().sort_values(ascending=False).reset_index().iloc[:8,]
    car_color_old = concat_accid['carcolor'].str[:1].value_counts().sort_values(ascending=False).reset_index().iloc[:8,]

    data_pair = car_color.values.tolist()

    bar = (
        Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f'{width}px',height=f'{height}px'))
        .add_xaxis([f"{i[0]}色" for i in data_pair])
        .add_yaxis('车辆颜色',[i[1] for i in data_pair],
                   label_opts=opts.LabelOpts(position='top',font_weight='bolder',color='cyan'),
                   itemstyle_opts=base_itemstyle)
        .set_global_opts(
            title_opts=opts.TitleOpts(title='不同车辆颜色事故发生次数柱状图',pos_left='center'),
            xaxis_opts=opts.AxisOpts(name='车辆颜色',
                                     name_location='center',
                                     name_gap=30,
                                     name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bolder'),
                                     axislabel_opts=opts.LabelOpts(color='cyan',font_size=16,font_weight='bolder'),
                                     axisline_opts=opts.AxisLineOpts(is_show=False),
                                     axistick_opts=opts.AxisTickOpts(is_show=False)),
            yaxis_opts=opts.AxisOpts(name='事故次数',
                                     name_location='center',name_gap=50,
                                     splitline_opts=opts.SplitLineOpts(is_show=False),
                                     axislabel_opts=opts.LabelOpts(color='cyan',font_weight='bolder'),
                                     name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bolder')),
            legend_opts=opts.LegendOpts(is_show=False),
            tooltip_opts=opts.TooltipOpts(trigger='axis',axis_pointer_type='shadow'),
            visualmap_opts=opts.VisualMapOpts(is_show=False,max_=7800,min_=50)

        )
    )
    return bar


# 汽车品牌分析
def get_pic2():
    from wordcloud import WordCloud
    new_accid['clpp'] = new_accid['clpp'].apply(lambda x:f"{re.sub('牌|汽车','',x)}牌")
    clpp_dict = new_accid['clpp'].value_counts().to_dict()
    clpp_dict.pop('-1牌')  # 将所有的-1牌提出
    wc = WordCloud(font_path='simhei')
    wc.fit_words(clpp_dict)
    wc.to_file('汽车品牌词云.png')

    words = list(zip(clpp_dict.keys(),clpp_dict.values()))
    from pyecharts.charts import WordCloud
    wc = (
        WordCloud(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
        .add('',words,word_size_range=[5,100],shape=SymbolType.DIAMOND)
        .set_global_opts(title_opts=opts.TitleOpts(title='汽车品牌词云图',
                                                   pos_left='center'),
                         legend_opts=opts.LegendOpts(is_show=False))
    )
    return wc


# 肇事者分析（性别）
def get_pic3():
    new_accid['sex'].value_counts()
    concat_accid['sex'].value_counts()
    concat_accid['sex'] = concat_accid['sex'].map({0:'女性',1:'男性'})
    data_pair = concat_accid.groupby(['driverresponsibility','sex']).agg({'sex':[('数量','count')]})
    dp1 = data_pair.loc['不负责任'].reset_index().values.tolist()
    dp2 = data_pair.loc['负全部责任'].reset_index().values.tolist()
    dp3 = data_pair.loc['负同等责任'].reset_index().values.tolist()

    pie = (Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
           .add('不负责任',dp1,center=['20%','45%'],radius=[30,80])
           .add('负全部责任', dp2, center=['50%', '45%'], radius=[30, 80])
           .add('负同等责任', dp3, center=['77%', '45%'], radius=[30, 80])
           .set_series_opts(label_opts=opts.LabelOpts(formatter="{a}:\n{b}:{c}\n占比{d}%"),
                            itemstyle_opts=itemstyle)
           )
    return pie


# 肇事者驾龄分析
def get_pic4():
    new_accid_tmp = new_accid.copy()
    new_accid_tmp = new_accid_tmp[new_accid_tmp['cclzrq'] != '-1']
    new_accid_tmp = new_accid_tmp[new_accid_tmp['cclzrq'] != '0001-01-01 00:00:00']
    new_accid_tmp['cclzrq'] = pd.to_datetime(new_accid_tmp['cclzrq'])
    new_accid_tmp['accidenttime'] = pd.to_datetime(new_accid_tmp['accidenttime'])

    # 计算驾龄
    time_diff = (new_accid_tmp['accidenttime'] - new_accid_tmp['cclzrq']).dt.days / 365
    new_accid_tmp['drive_year'] = time_diff.apply(lambda x:round(x,1))

    # 对驾龄进行区间划分
    bins = list(range(0,52,3))
    carage_group = pd.cut(new_accid_tmp['drive_year'],bins,right=False)

    # 处理数据
    dp = carage_group.value_counts().reset_index()
    dp['drive_year'] = dp['drive_year'].astype('str')
    data_pair = dp.values.tolist()

    bar1 = (Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
            .add_xaxis([i[0] for i in data_pair])
            .add_yaxis('驾龄',data_pair,
                       label_opts=opts.LabelOpts(position='top',font_weight='bold',color='cyan'),
                       itemstyle_opts=base_itemstyle)
            .set_global_opts(title_opts=opts.TitleOpts(title='不同驾龄段事故发生次数统计',pos_left='center'),
                             xaxis_opts=opts.AxisOpts(name='年龄段',
                                                      name_location='center',
                                                      name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bold'),
                                                      axislabel_opts=opts.LabelOpts(color='cyan',font_size=16,font_weight='bold'),
                                                      axisline_opts=opts.AxisLineOpts(is_show=False),
                                                      axistick_opts=opts.AxisTickOpts(is_show=False),
                                                      splitline_opts=opts.SplitLineOpts(is_show=False)
                                                      ),
                             yaxis_opts=opts.AxisOpts(name='事故次数',
                                                      name_location='center',name_gap=50,
                                                      splitline_opts=opts.SplitLineOpts(is_show=False),
                                                      axislabel_opts=opts.LabelOpts(color='cyan',font_weight='bold'),
                                                      name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bold')),
                             legend_opts=opts.LegendOpts(is_show=True,pos_left='5%'),
                             tooltip_opts=opts.TooltipOpts(trigger='axis',
                                                           axis_pointer_type='shadow'),
                             visualmap_opts=opts.VisualMapOpts(is_show=False,max_=7800,min_=50))
            )
    return bar1


# 年龄分析
def get_pic5():
    new_accid_tmp = new_accid.copy()
    new_accid_tmp = new_accid_tmp[~new_accid_tmp['brith'].str.contains('P|D|号')]
    new_accid_tmp['age'] = 2015 - new_accid_tmp['brith'].apply(lambda x:str(x)[:4]).astype(int)
    bins2 = list(range(19,80,5))
    age_group = pd.cut(new_accid_tmp['age'],bins2,right=False)
    dp4 = age_group.value_counts().sort_index().reset_index()
    dp4['age'] = dp4['age'].astype('str')
    data_pair2 = dp4.values.tolist()
    bar2 = (Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
            .add_xaxis([i[0] for i in data_pair2])
            .add_yaxis('年龄',data_pair2,
                       label_opts=opts.LabelOpts(position='top',font_weight='bolder',color='cyan'),
                       itemstyle_opts=base_itemstyle)
            .set_global_opts(title_opts=opts.TitleOpts(title='不同年龄段事故发生次数统计',pos_left='center'),
                             xaxis_opts=opts.AxisOpts(name='数量',
                                                      name_location='center',
                                                      name_gap=40,
                                                      name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bolder'),
                                                      axisline_opts=opts.AxisLineOpts(is_show=False),
                                                      axistick_opts=opts.AxisTickOpts(is_show=False),
                                                      splitline_opts=opts.SplitLineOpts(is_show=False)),
                             yaxis_opts=opts.AxisOpts(name='事故次数',
                                                      name_location='center',name_gap=50,
                                                      splitline_opts=opts.SplitLineOpts(is_show=False),
                                                      axislabel_opts=opts.LabelOpts(color='cyan',font_weight='bold'),
                                                      name_textstyle_opts=opts.TextStyleOpts(color='cyan',font_size=16,font_weight='bold')),
                             legend_opts = opts.LegendOpts(is_show=True,pos_left='5%'),
                             tooltip_opts=opts.TooltipOpts(trigger='axis',
                                                           axis_pointer_type='shadow'),
                             visualmap_opts=opts.VisualMapOpts(is_show=False,max_=7800,min_=50)
                             )
            )
    return bar2


# 事故类型分析
def get_pic6():
    sex_driverfault = new_accid.groupby(by=['sex','driverfault']).size().unstack().T.reset_index()
    sex_driverfault.columns = ['事故类型','女性','男性']

    dp_female = sex_driverfault[['事故类型','女性']].sort_values(by='女性',ascending=False).values.tolist()
    dp_male = sex_driverfault[['事故类型', '男性']].sort_values(by='男性', ascending=False).values.tolist()

    pie1 = (Pie(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
            .add('女性',dp_female,center=['20%','45%'],radius=[30,80],rosetype='area')
            .add('男性',dp_male,center=['65%','45%'],radius=[30,80],rosetype='area')
            .set_series_opts(label_opts=opts.LabelOpts(formatter='{b}:{c}\n占比{d}%'),
                             itemstyle_opts=itemstyle)
            .set_global_opts(title_opts=opts.TitleOpts(title='不同性别的事故类型分析',pos_left='center'),
                             legend_opts=opts.LegendOpts(pos_left='8%')))
    return pie1


# 事故类型发生的时间点分析（月份角度）
def get_pic7():
    new_accid_tmp = new_accid.copy()
    new_accid_tmp['accidenttime'] = pd.to_datetime(new_accid_tmp['accidenttime'])
    new_accid_tmp['month'] = new_accid_tmp['accidenttime'].dt.month
    new_accid_tmp['hour'] = new_accid_tmp['accidenttime'].dt.hour
    data_p = new_accid_tmp.groupby(['month','hour']).size().unstack().fillna(value=0).stack().reset_index()
    from sklearn.preprocessing import MinMaxScaler
    scaler = MinMaxScaler(feature_range=(1,50))
    data_p['point_size'] = scaler.fit_transform(data_p[[0]]).astype('int')
    month_list = ['一月','二月','三月','四月','五月']
    data_p['month'] = data_p['month'].map(dict(zip(range(1,6),month_list)))
    data_pair = data_p.values.tolist()

    hours = [
        '0a/12p','1a','2a','3a','4a','5a','6a','7a','8a','9a','10a',
        '11a','12a/0p','1p','2p','3p','4p','5p','6p','7p','8p','9p',
        '10p','11p'
    ]
    single_axis,titles = [],[]
    scatter = Scatter(init_opts=opts.InitOpts(theme=ThemeType.DARK,width=f"{width}px",height=f"{height}px"))
    for idx,month in enumerate(month_list):
        scatter.add_xaxis(hours)
        single_axis.append({
            'left':100,
            'nameGap':20,
            'nameLocation':'start',
            'type':'category',
            'data':hours,
            'top':f"{idx * 100 / 5 + 5}",
            'height':f"{100 / 5 - 10}",
            'gridIndex':idx,
            'axisLabel':{
                'interval':2,
                'color':'cyan'
            }
        })
        titles.append(
            dict(text=month,
                 top=f"{idx * 100 / 5 + 5}",
                 left='2%',
                 textStyle=dict(color='cyan',weight='bolder'))
        )
        scatter.add_yaxis(
            '',
            y_axis=[[i[2],i[3]] for i in data_pair if i[0] == month],
            symbol_size=JsCode('function(p){console.log(p);return p[2];}')
        )
        scatter.options['series'][idx]['coordinateSystem'] = 'singleAxis'
        scatter.options['series'][idx]['singleAxisIndex'] = idx
    scatter.options['singleAxis'] = single_axis
    scatter.set_global_opts(
        title_opts=titles,
        legend_opts=opts.LegendOpts(is_show=False),
        xaxis_opts=opts.AxisOpts(is_show=False),
        tooltip_opts=opts.TooltipOpts(formatter=JsCode(
           "function(p){console.log(p); return '时间:' + p.data[0] + ' 事故数量' + String(p.data[2]);}"
        ))
    )
    return scatter


